{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 变分量子线路梯度计算进阶\n",
    "\n",
    "[![下载Notebook](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_notebook.png)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/master/mindquantum/zh_cn/mindspore_get_gradient_of_PQC_with_mindquantum.ipynb)&emsp;\n",
    "[![下载样例代码](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_download_code.png)](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/notebook/master/mindquantum/zh_cn/mindspore_get_gradient_of_PQC_with_mindquantum.py)&emsp;\n",
    "[![查看源文件](https://mindspore-website.obs.cn-north-4.myhuaweicloud.com/website-images/master/resource/_static/logo_source.png)](https://gitee.com/mindspore/docs/blob/master/docs/mindquantum/docs/source_zh_cn/get_gradient_of_PQC_with_mindquantum.ipynb)\n",
    "\n",
    "在MindQuantum中，我们可以通过`Simulator`类的`get_expectation_with_grad`方法来获得一个变分量子线路的梯度，在这篇教程中，我们将更进一步的介绍该方法的其他功能，帮助大家来实现更高级的使用方法。\n",
    "\n",
    "## 模型介绍\n",
    "\n",
    "`get_expectation_with_grad`方法主要是用来计算如下表达式的值和线路中参数的梯度。\n",
    "\n",
    "$$E(\\boldsymbol{\\theta})=\\left<\\varphi\\right|U^\\dagger_l(\\boldsymbol{\\theta})HU_r(\\boldsymbol{\\theta})\\left|\\psi\\right>$$\n",
    "\n",
    "该方法的接口定义如下\n",
    "\n",
    "```python\n",
    "Simulator.get_expectation_with_grad(\n",
    "    hams,\n",
    "    circ_right,\n",
    "    circ_left=None,\n",
    "    simulator_left=None,\n",
    "    encoder_params_name=None,\n",
    "    ansatz_params_name=None,\n",
    "    parallel_worker=None\n",
    ")\n",
    "```\n",
    "\n",
    "下面，我们将一一介绍每个参数的意义。\n",
    "\n",
    "1. `hams`。线路中的哈密顿量，所需要的类型为MindQuantum中的`Hamiltonian`，或者一个包含多个`Hamiltonian`的`list`数组，对于后一种情况，框架会同时计算出线路关于所有哈密顿量的期望值，和每个期望值关于线路参数的梯度\n",
    "\n",
    "2. `circ_right`。为公式中的$U_r(\\boldsymbol{\\theta})$\n",
    "\n",
    "3. `circ_left`。为公式中的$U_l(\\boldsymbol{\\theta})$，当为默认值`None`时，`circ_left`和`circ_right`为同一线路,若需要空线路可单独使用Circuit()创建。\n",
    "\n",
    "4. `simulator_left`。为包含公式中$\\left|\\varphi\\right>$的模拟器，你可以通过模拟器的`set_qs`、`apply_gate`或`apply_circuit`方法来设置该模拟器的状态为你需要的状态。当为默认值`None`时，$\\left|\\varphi\\right>=\\left|\\psi\\right>$，而$\\left|\\psi\\right>$为当前模拟器所包含的量子态。\n",
    "\n",
    "5. `encoder_params_name`。表明$U_l(\\boldsymbol{\\theta})$和$U_r(\\boldsymbol{\\theta})$中，哪些含参量子门是encoder。在量子神经网络中，encoder对应的参数是用户需要输入的数，不参与训练。当为默认值`None`时，线路中没有encoder。\n",
    "\n",
    "6. `ansatz_params_name`。表明$U_l(\\boldsymbol{\\theta})$和$U_r(\\boldsymbol{\\theta})$中，哪些含参量子门是ansatz。在量子神经网络中，ansatz对应的参数由系统或用户初始化，随后由系统根据梯度来更新，参与训练。当为默认值`None`时，线路中的所有参数门都是ansatz。\n",
    "\n",
    "7. `parallel_worker`。当`hams`包含多个哈密顿量或者encoder的输入包含多个样本点时，MindQuantum会根据此整数为参考来合理地进行并行运算。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 多个哈密顿量在多个输入样本点下的期望值\n",
    "\n",
    "在本任务中，我们想计算如下量子线路在$\\alpha=\\text{arctan}(\\sqrt{2}), \\pi/2$时，关于哈密顿量$Z_0, X_0, Y_0$的期望值。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": "<div class=\"nb-html-output output_area\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"1216.8\" height=\"80\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n<rect x=\"0\" y=\"0\" width=\"1216.8\" height=\"80\" fill=\"#ffffff\" />\n<text x=\"20.0\" y=\"40.0\" font-size=\"16px\" dominant-baseline=\"middle\" text-anchor=\"start\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#252b3a\" >\nq0:\n </text>\n<line x1=\"48.8\" x2=\"1196.8\" y1=\"40.0\" y2=\"40.0\" stroke=\"#adb0b8\" stroke-width=\"1\" />\n\n<rect x=\"72.8\" y=\"20.0\" width=\"120.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" />\n<text x=\"132.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nRY\n </text>\n<text x=\"132.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\n√2/8*alpha\n </text>\n\n\n<rect x=\"212.8\" y=\"20.0\" width=\"120.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" />\n<text x=\"272.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nRX\n </text>\n<text x=\"272.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\n-√2/8*alpha\n </text>\n\n\n<rect x=\"352.8\" y=\"20.0\" width=\"120.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" />\n<text x=\"412.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nRY\n </text>\n<text x=\"412.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\n√2/8*alpha\n </text>\n\n\n<rect x=\"492.8\" y=\"20.0\" width=\"120.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" />\n<text x=\"552.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nRX\n </text>\n<text x=\"552.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\n-√2/8*alpha\n </text>\n\n\n<rect x=\"632.8\" y=\"20.0\" width=\"120.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" />\n<text x=\"692.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nRY\n </text>\n<text x=\"692.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\n√2/8*alpha\n </text>\n\n\n<rect x=\"772.8\" y=\"20.0\" width=\"120.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" />\n<text x=\"832.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nRX\n </text>\n<text x=\"832.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\n-√2/8*alpha\n </text>\n\n\n<rect x=\"912.8\" y=\"20.0\" width=\"120.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" />\n<text x=\"972.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nRY\n </text>\n<text x=\"972.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\n√2/8*alpha\n </text>\n\n\n<rect x=\"1052.8\" y=\"20.0\" width=\"120.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" />\n<text x=\"1112.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nRX\n </text>\n<text x=\"1112.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\n-√2/8*alpha\n </text>\n\n</svg></div>",
      "text/plain": [
       "<mindquantum.io.display.circuit_svg_drawer.SVGCircuit at 0x7f5153ce2d60>"
      ]
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import numpy as np\n",
    "from mindquantum import QubitOperator\n",
    "from mindquantum import Simulator\n",
    "from mindquantum import Circuit, TimeEvolution, Hamiltonian, H\n",
    "\n",
    "# 定义希尔伯特空间中的旋转轴\n",
    "axis = QubitOperator('Y0', 1 / np.sqrt(2)) + QubitOperator('X0', -1 / np.sqrt(2))\n",
    "# 定义trotter分解的阶数\n",
    "trotter_order = 4\n",
    "# 利用TimeEvolution来对旋转进行trotter分解\n",
    "encoder = TimeEvolution(axis, {'alpha': 0.5 / trotter_order}).circuit * trotter_order\n",
    "encoder.svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "下面定义待求期望值的哈密顿量："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[1 [X0] , 1 [Y0] , 1 [Z0] ]"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 定义哈密顿量集合\n",
    "hams = [Hamiltonian(QubitOperator('X0')), Hamiltonian(QubitOperator('Y0')), Hamiltonian(QubitOperator('Z0'))]\n",
    "hams"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获取求期望值和梯度的算子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<mindquantum.simulator.simulator.GradOpsWrapper at 0x7f5153c6c790>"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "grad_ops = Simulator('projectq', 1).get_expectation_with_grad(hams, encoder, encoder_params_name=encoder.params_name, parallel_worker=6)\n",
    "grad_ops"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "定义`alpha`的值："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[0.95531662],\n",
       "       [1.57079633]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "alpha = np.array([[np.arctan(np.sqrt(2))], [np.pi/2]])\n",
    "alpha"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.59389047+0.j 0.55828416+0.j 0.57932107+0.j]\n",
      " [0.77269648+0.j 0.63465887+0.j 0.01217645+0.j]]\n",
      "shape: (2, 3)\n",
      "\n",
      "\n",
      "[[[ 0.45790207+0.j]\n",
      "  [ 0.35200884+0.j]\n",
      "  [-0.80864423+0.j]]\n",
      "\n",
      " [[ 0.10989151+0.j]\n",
      "  [-0.11512098+0.j]\n",
      "  [-0.9732094 +0.j]]]\n",
      "shape: (2, 3, 1)\n"
     ]
    }
   ],
   "source": [
    "f, g = grad_ops(alpha)\n",
    "print(f)\n",
    "print(f'shape: {f.shape}')\n",
    "print('\\n')\n",
    "print(g)\n",
    "print(f'shape: {g.shape}')"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 结果分析\n",
    "\n",
    "根据上面结果我们可以看到，期望值`f`的维度为`(2, 3)`，不难发现，`f`的每一行对应每一个样本点不同哈密顿量期望值，`f`的每一列对应每个哈密顿量在不同样本的下的期望值。而对于梯度`g`来说，我们也有相似的结论，只不过最后一个维度表示的是不同的线路参数。\n",
    "\n",
    "## 计算不同量子态的内积\n",
    "\n",
    "根据模型，我们只需将哈密顿量设置为单位算符，$U_l(\\boldsymbol{\\theta})$ 设置为空的量子线路，那么我们就可以利用 $U_r(\\boldsymbol{\\theta})$ 来将 $\\left|\\psi\\right>$ 旋转到 $\\left|\\varphi\\right>$上，而这需要计算出 $\\left|\\varphi\\right>$和旋转后的量子态之间的内积。\n",
    "\n",
    "这里，我们计算如下量子线路对零态进行演化过后的量子态与均匀叠加态之间的内积。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/svg+xml": "<div class=\"nb-html-output output_area\"><svg xmlns=\"http://www.w3.org/2000/svg\" width=\"276.8\" height=\"80\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n<rect x=\"0\" y=\"0\" width=\"276.8\" height=\"80\" fill=\"#ffffff\" />\n<text x=\"20.0\" y=\"40.0\" font-size=\"16px\" dominant-baseline=\"middle\" text-anchor=\"start\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#252b3a\" >\nq0:\n </text>\n<line x1=\"48.8\" x2=\"256.8\" y1=\"40.0\" y2=\"40.0\" stroke=\"#adb0b8\" stroke-width=\"1\" />\n\n<rect x=\"72.8\" y=\"20.0\" width=\"40.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" />\n<text x=\"92.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nRY\n </text>\n<text x=\"92.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\na\n </text>\n\n\n<rect x=\"132.8\" y=\"20.0\" width=\"40.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" />\n<text x=\"152.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nRZ\n </text>\n<text x=\"152.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nb\n </text>\n\n\n<rect x=\"192.8\" y=\"20.0\" width=\"40.0\" height=\"40\" rx=\"4\" ry=\"4\" stroke=\"#ffffff\" stroke-width=\"0\" fill=\"#fac209\" fill-opacity=\"1\" />\n<text x=\"212.8\" y=\"36.0\" font-size=\"20px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nRY\n </text>\n<text x=\"212.8\" y=\"52.0\" font-size=\"14.0px\" dominant-baseline=\"middle\" text-anchor=\"middle\" font-family=\"Arial\" font-weight=\"normal\" fill=\"#ffffff\" >\nc\n </text>\n\n</svg></div>",
      "text/plain": [
       "<mindquantum.io.display.circuit_svg_drawer.SVGCircuit at 0x7f51985feb50>"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "circuit = Circuit().ry('a', 0).rz('b', 0).ry('c', 0)\n",
    "circuit.svg()"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "制备包含均匀叠加态的模拟器："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "projectq simulator with 1 qubit (little endian).\n",
       "Current quantum state:\n",
       "√2/2¦0⟩\n",
       "√2/2¦1⟩"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "sim_l = Simulator('projectq', 1)\n",
    "sim_l.apply_gate(H.on(0))\n",
    "sim_l"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "制备单位哈密顿量："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [],
   "source": [
    "ham = Hamiltonian(QubitOperator(\"\"))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "获取内积和梯度计算算子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [],
   "source": [
    "grad_ops = Simulator('projectq', 1).get_expectation_with_grad(ham, circuit, Circuit(), simulator_left=sim_l)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "选择合适的参数："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [],
   "source": [
    "rot_angle = np.array([7.902762e-01, 2.139225e-04, 7.795934e-01])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "[[0.99999989-7.52279618e-05j]]\n",
      "\n",
      "\n",
      "[[[ 2.31681689e-04+3.80179652e-05j -5.34806192e-05-3.51659884e-01j\n",
      "    2.31681689e-04-3.80179652e-05j]]]\n"
     ]
    }
   ],
   "source": [
    "f, g = grad_ops(rot_angle)\n",
    "print(f)\n",
    "print('\\n')\n",
    "print(g)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 结果分析\n",
    "\n",
    "通过计算结果，我们发现最后两个态的内积接近于1，说明我们能够通过如上线路以很高的保真度制备一个均匀叠加态。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "(0.7074343486186319-0.00010695972396782116j)¦0⟩\n",
      "(0.7067790538448511+√5/3906250j)¦1⟩\n"
     ]
    }
   ],
   "source": [
    "print(circuit.get_qs(pr=rot_angle, ket=True))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "若想查询更多关于MindQuantum的API，请点击：[https://mindspore.cn/mindquantum/](https://mindspore.cn/mindquantum/)。"
   ]
  }
 ],
 "metadata": {
  "interpreter": {
   "hash": "d62cf896b9ca57de08105ce3983377439eacacf6f6599f9150bf400edf4fa4b8"
  },
  "kernelspec": {
   "display_name": "MindSpore",
   "language": "python",
   "name": "mindspore"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.8.8"
  },
  "orig_nbformat": 4
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
